1   /*
2    * Copyright (C) 2012 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import static com.google.common.base.Preconditions.checkNotNull;
20  
21  import java.util.Iterator;
22  import java.util.LinkedList;
23  import java.util.Queue;
24  
25  /**
26   * Views elements of a type {@code T} as nodes in a tree, and provides methods to traverse the trees
27   * induced by this traverser.
28   * 
29   * <p>For example, the tree <pre>   {@code
30   *
31   *          h
32   *        / | \
33   *       /  e  \
34   *      d       g
35   *     /|\      |
36   *    / | \     f
37   *   a  b  c
38   *   }</pre>
39   *   
40   * can be iterated over in preorder (hdabcegf), postorder (abcdefgh), or breadth-first order
41   * (hdegabc).
42   * 
43   * <p>Null nodes are strictly forbidden.
44   *
45   * @author Louis Wasserman
46   */
47  public abstract class TreeTraverser<T> {
48    
49    /**
50     * Returns the children of the specified node.  Must not contain null.
51     */
52    public abstract Iterable<T> children(T root);
53  
54    /**
55     * Returns an unmodifiable iterable over the nodes in a tree structure, using pre-order
56     * traversal. That is, each node's subtrees are traversed after the node itself is returned.
57     *
58     * <p>No guarantees are made about the behavior of the traversal when nodes change while
59     * iteration is in progress or when the iterators generated by {@link #children} are advanced.
60     */
61    public final FluentIterable<T> preOrderTraversal(final T root) {
62      checkNotNull(root);
63      return new FluentIterable<T>() {
64        @Override
65        public UnmodifiableIterator<T> iterator() {
66          return preOrderIterator(root);
67        }
68      };
69    }
70  
71    // overridden in BinaryTreeTraverser
72    UnmodifiableIterator<T> preOrderIterator(T root) {
73      return new PreOrderIterator(root);
74    }
75  
76    private final class PreOrderIterator extends UnmodifiableIterator<T> {
77      private final LinkedList<Iterator<T>> stack;
78  
79      PreOrderIterator(T root) {
80        this.stack = Lists.newLinkedList();
81        stack.addLast(Iterators.singletonIterator(checkNotNull(root)));
82      }
83  
84      @Override
85      public boolean hasNext() {
86        return !stack.isEmpty();
87      }
88  
89      @Override
90      public T next() {
91        Iterator<T> itr = stack.getLast(); // throws NSEE if empty
92        T result = checkNotNull(itr.next());
93        if (!itr.hasNext()) {
94          stack.removeLast();
95        }
96        Iterator<T> childItr = children(result).iterator();
97        if (childItr.hasNext()) {
98          stack.addLast(childItr);
99        }
100       return result;
101     }
102   }
103 
104   /**
105    * Returns an unmodifiable iterable over the nodes in a tree structure, using post-order
106    * traversal. That is, each node's subtrees are traversed before the node itself is returned.
107    *
108    * <p>No guarantees are made about the behavior of the traversal when nodes change while
109    * iteration is in progress or when the iterators generated by {@link #children} are advanced.
110    */
111   public final FluentIterable<T> postOrderTraversal(final T root) {
112     checkNotNull(root);
113     return new FluentIterable<T>() {
114       @Override
115       public UnmodifiableIterator<T> iterator() {
116         return postOrderIterator(root);
117       }
118     };
119   }
120 
121   // overridden in BinaryTreeTraverser
122   UnmodifiableIterator<T> postOrderIterator(T root) {
123     return new PostOrderIterator(root);
124   }
125 
126   private static final class PostOrderNode<T> {
127     final T root;
128     final Iterator<T> childIterator;
129 
130     PostOrderNode(T root, Iterator<T> childIterator) {
131       this.root = checkNotNull(root);
132       this.childIterator = checkNotNull(childIterator);
133     }
134   }
135 
136   private final class PostOrderIterator extends AbstractIterator<T> {
137     private final LinkedList<PostOrderNode<T>> stack;
138 
139     PostOrderIterator(T root) {
140       this.stack = Lists.newLinkedList();
141       stack.addLast(expand(root));
142     }
143 
144     @Override
145     protected T computeNext() {
146       while (!stack.isEmpty()) {
147         PostOrderNode<T> top = stack.getLast();
148         if (top.childIterator.hasNext()) {
149           T child = top.childIterator.next();
150           stack.addLast(expand(child));
151         } else {
152           stack.removeLast();
153           return top.root;
154         }
155       }
156       return endOfData();
157     }
158 
159     private PostOrderNode<T> expand(T t) {
160       return new PostOrderNode<T>(t, children(t).iterator());
161     }
162   }
163 
164   /**
165    * Returns an unmodifiable iterable over the nodes in a tree structure, using breadth-first
166    * traversal. That is, all the nodes of depth 0 are returned, then depth 1, then 2, and so on.
167    *
168    * <p>No guarantees are made about the behavior of the traversal when nodes change while
169    * iteration is in progress or when the iterators generated by {@link #children} are advanced.
170    */
171   public final FluentIterable<T> breadthFirstTraversal(final T root) {
172     checkNotNull(root);
173     return new FluentIterable<T>() {
174       @Override
175       public UnmodifiableIterator<T> iterator() {
176         return new BreadthFirstIterator(root);
177       }
178     };
179   }
180 
181   private final class BreadthFirstIterator extends UnmodifiableIterator<T>
182       implements PeekingIterator<T> {
183     private final Queue<T> queue;
184 
185     BreadthFirstIterator(T root) {
186       this.queue = Lists.newLinkedList();
187       queue.add(checkNotNull(root));
188     }
189 
190     @Override
191     public boolean hasNext() {
192       return !queue.isEmpty();
193     }
194 
195     @Override
196     public T peek() {
197       return queue.element();
198     }
199 
200     @Override
201     public T next() {
202       T result = queue.remove();
203       for (T child : children(result)) {
204         queue.add(checkNotNull(child));
205       }
206       return result;
207     }
208   }
209 }